package com.gitee.jmash.rbac.client.shiro.grpc;

import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import com.crenjoy.proto.beanutils.ProtoBeanUtils;
import com.gitee.jmash.common.grpc.GrpcContext;
import com.gitee.jmash.common.security.JmashPrincipal;
import com.gitee.jmash.core.grpc.cdi.GrpcServerInterceptor;
import com.gitee.jmash.core.utils.TenantUtil;
import com.gitee.jmash.rbac.client.shiro.exception.TenantPermitException;
import io.grpc.ForwardingServerCallListener;
import io.grpc.Metadata;
import io.grpc.ServerCall;
import io.grpc.ServerCall.Listener;
import io.grpc.ServerCallHandler;
import io.grpc.ServerInterceptor;
import io.grpc.Status;
import jakarta.annotation.Priority;

/**
 * 跨租户的权限越权控制.
 *
 * @author cgd
 *
 */
@GrpcServerInterceptor
@Priority(2200)
public class ShiroTenantInterceptor implements ServerInterceptor {

  private static final Log log = LogFactory.getLog(ShiroTenantInterceptor.class);

  @Override
  public <ReqT, RespT> Listener<ReqT> interceptCall(ServerCall<ReqT, RespT> call, Metadata headers,
      ServerCallHandler<ReqT, RespT> next) {
    try {
      return new ContextualizedServerCallListener<>(next.startCall(call, headers), call);
    } catch (Throwable ex) {
      log.error("", ex);
      return next.startCall(call, headers);
    }
  }


  /**
   * 客户端请求处理过程.
   */
  private static class ContextualizedServerCallListener<ReqT, RespT>
      extends ForwardingServerCallListener.SimpleForwardingServerCallListener<ReqT> {

    private boolean valid = true;

    private TenantPermitException ex;

    private ServerCall<ReqT, RespT> call;

    Pattern pattern = Pattern.compile("[pe]\\d{2,5}");

    public ContextualizedServerCallListener(ServerCall.Listener<ReqT> delegate,
        ServerCall<ReqT, RespT> call) {
      super(delegate);
      this.call = call;
    }

    @Override
    public void onMessage(ReqT message) {
      super.onMessage(message);
      // 获取租户信息
      String tenant = null;
      try {
        tenant = ProtoBeanUtils.getSimpleProperty(message, "tenant");
      } catch (Exception ex) {
      }
      if (StringUtils.isBlank(tenant)) {
        return;
      }
      // 获取用户登录信息.
      JmashPrincipal principal = GrpcContext.getPrincipal();
      if (principal == null) {
        return;
      }
      // 平台用户允许跨租户访问.
      if (StringUtils.equals("core", principal.getTenant())) {
        return;
      }
      // 访问个人数据
      String storage = principal.getStorage();
      if (StringUtils.equals(tenant, storage)) {
        return;
      }
      // 跨租户的权限越权
      String tenantName = TenantUtil.getTenantName(tenant);
      // TODO 访问数据个人或组织数据.
      Matcher matcher = pattern.matcher(tenantName);
      if (matcher.matches()) {
        return;
      }
      valid =
          (StringUtils.isBlank(tenantName) || StringUtils.equals(tenantName, principal.getTenant())
              || StringUtils.equals(tenant, principal.getTenant()))
              || (!TenantUtil.hasTenantIdentifier(tenant)
                  && TenantUtil.hasTenantIdentifier(principal.getTenant()));
      if (!valid) {
        ex = new TenantPermitException(tenant, principal);
      }
    }

    @Override
    public void onHalfClose() {
      // 检查请求是否有效
      if (!valid) {
        log.error(ex.getMessage());
        this.call.close(Status.PERMISSION_DENIED.withDescription(ex.getMessage()), new Metadata());
        return;
      }
      super.onHalfClose();
    }
  }


}
